/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
					     owned_scriptable_adv_object.cpp

	$Header: /game/owned_scriptable_adv_object.cpp $

	$NoKeywords: $

 ************************************************************************/

#include "precompiled.h"
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "owned_scriptable_adv_object.h"

#include <cassert>

#include "abstract_script_action.h"
#include "adventure_frame.h"
#include "adventure_map.h"
#include "ownable_event.h"
#include "player_color.h"
#include "sized_int_types.h"
#include "streambuf_operators.h"
#include "string_insensitive_compare.h"

// --------------------------------------------------------------------------
// Unnamed namespace
// --------------------------------------------------------------------------

namespace
{

	int const k_current_format_version = 2;
	int const k_current_map_format_version = 2;

} // Unnamed namespace

// --------------------------------------------------------------------------
// t_owned_scriptable_adv_object members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
void t_owned_scriptable_adv_object::copy_events( t_owned_scriptable_adv_object & target, t_owned_scriptable_adv_object const & source )
{
	target.m_triggerable_events = source.m_triggerable_events;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
int t_owned_scriptable_adv_object::get_version() const
{
	return k_current_format_version;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_owned_scriptable_adv_object::read(
	std::streambuf &					stream,
	t_qualified_adv_object_type const &	type,
	int									version )
{
	assert( version >= 0 && version <= k_current_format_version );

	if ( version < 1 )
		return true;

	if ( !t_owned_adv_object::read( stream, type, version ) )
		return false;

	return version < 2 || read_events( stream, version );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_owned_scriptable_adv_object::write( std::streambuf & stream ) const
{
	return t_owned_adv_object::write( stream ) && write_events( stream );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_owned_scriptable_adv_object::read_from_map(
	std::streambuf &		stream,
	t_progress_handler *	handler,
	int						version )
{
	assert( version >= 0 && version <= k_current_map_format_version );

	t_player_color new_owner_color;
	if ( version >= 1 )
	{
		new_owner_color = t_player_color( get< t_uint8 >( stream ) );
		if ( new_owner_color < 0 || new_owner_color >= k_player_color_count )
			return false;
	}
	else
		new_owner_color = k_player_gray;
	set_player_color( new_owner_color );

	return version < 2 || read_events_from_map( stream, version );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_owned_scriptable_adv_object::read_events(
	std::streambuf &	stream,
	int					version )
{
	int script_version = get< t_uint16 >( stream );
	if ( script_version < 0 || script_version > t_abstract_script_action::get_version() )
		return false;

	int count = get< t_uint16 >( stream );

	t_triggerable_event_list new_events;
	new_events.reserve( count );

	while ( count > 0 )
	{
		t_triggerable_event_ptr new_event_ptr( new t_triggerable_event );
		if ( !new_event_ptr->read( stream, script_version ) )
			return false;
		new_events.push_back( new_event_ptr );

		--count;
	}

	m_triggerable_events.swap( new_events );

	return true;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_owned_scriptable_adv_object::read_events_from_map(
	std::streambuf &	stream,
	int					version )
{
	int count = get< t_uint16 >( stream );

	t_triggerable_event_list new_events;
	new_events.reserve( count );

	while ( count > 0 )
	{
		t_triggerable_event_ptr new_event_ptr( new t_triggerable_event );
		if ( !new_event_ptr->read_from_map( stream ) )
			return false;
		new_events.push_back( new_event_ptr );

		--count;
	}

	m_triggerable_events.swap( new_events );

	return true;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
bool t_owned_scriptable_adv_object::write_events(
	std::streambuf &	stream ) const
{
	put< t_uint16 >( stream, t_abstract_script_action::get_version() );
	put< t_uint16 >( stream, m_triggerable_events.size() );

	typedef t_triggerable_event_list::const_iterator t_event_iter;
	t_event_iter event_end = m_triggerable_events.end();
	t_event_iter event_iter = m_triggerable_events.begin();
	for ( ; event_iter != event_end; ++event_iter )
	{
		if ( !( *event_iter )->write( stream ) )
			return false;
	}

	return true;
}

bool t_owned_scriptable_adv_object::process_triggerable_events( t_adventure_map& map, std::string const& name )
{
	bool result = false;

	int size = m_triggerable_events.size();
	for (int i = 0; i < size; i++) {
		t_triggerable_event_ptr & event = m_triggerable_events[i];
		if (( string_insensitive_compare(event->get_name(), name) == 0 )
			&& event->ownership_test(get_owner()) )
		{
			event->execute_effects(map.get_current_player(), get_adventure_frame());
			t_triggerable_event::t_script const & script = event->get_script();
			script.execute(t_script_context_object(&map, this));
			if( map.is_game_over() )
				return false;

			if (script.pending_removal()) {
				script.clear_removal();
				event = new t_ownable_triggerable_event;
			}
			result = true;
		}
	}

	if ( result )
		get_adventure_frame()->update();

	return result;
}

